package top.xzxsrq.fileviewutils.plugin;

import lombok.extern.log4j.Log4j2;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 自定义插件jar包的加载类
 */
@Log4j2
public class JarDynamicLoadClassLoader extends URLClassLoader {

    private final Map<String, Class<?>> loadedClasses = new ConcurrentHashMap<>();
    private final static Map<String, JarDynamicLoadClassLoader> pluginClassLoaderCenter = new ConcurrentHashMap<>();


    public Map<String, Class<?>> getLoadedClasses() {
        return loadedClasses;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // 从已加载的类集合中获取指定名称的类
        Class<?> clazz = loadedClasses.get(name);
        if (clazz != null) {
            return clazz;
        }
        // 调用父类的findClass方法加载指定名称的类
        clazz = super.findClass(name);
        // 将加载的类添加到已加载的类集合中
        loadedClasses.put(name, clazz);
        return clazz;
    }

    private void unload() {
        try {
            for (Map.Entry<String, Class<?>> entry : loadedClasses.entrySet()) {
                // 从已加载的类集合中移除该类
                String className = entry.getKey();
                loadedClasses.remove(className);
                try {
                    // 调用该类的destory方法，回收资源
                    Class<?> clazz = entry.getValue();
                    Method destory = clazz.getDeclaredMethod("destory");
                    destory.invoke(clazz);
                } catch (Exception e) {
                    log.error("{}：类没有销毁方法：destory",className);
                }
            }
            // 从其父类加载器的加载器层次结构中移除该类加载器
            close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private JarDynamicLoadClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public static Map<String, Class<?>> loadJar(String path, ClassLoader parent) {
        File file = new File(path);
        try {
            // URLClassloader加载jar包规范必须这么写
            URL url = new URL("jar:file:" + file.getAbsolutePath() + "!/");
            URLConnection urlConnection = url.openConnection();
            JarURLConnection jarURLConnection = (JarURLConnection) urlConnection;
            // 获取jar文件
            JarFile jarFile = jarURLConnection.getJarFile();
            Enumeration<JarEntry> entries = jarFile.entries();
            JarDynamicLoadClassLoader jarDynamicLoadClassLoader = new JarDynamicLoadClassLoader(new URL[]{url}, parent);
            // 遍历文件
            while (entries.hasMoreElements()) {
                JarEntry jarEntry = entries.nextElement();
                if (jarEntry.getName().endsWith(".class")) {
                    // 1. 加载类到jvm中
                    // 获取类的全路径名
                    String className = jarEntry.getName().replace('/', '.').substring(0, jarEntry.getName().length() - 6);
                    // 1.1进行反射获取
                    jarDynamicLoadClassLoader.findClass(className);
                }
            }
            pluginClassLoaderCenter.put(path, jarDynamicLoadClassLoader);
            return jarDynamicLoadClassLoader.loadedClasses;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Map<String, Class<?>> loadJar(String path) {
        return loadJar(path, JarDynamicLoadClassLoader.class.getClassLoader());
    }

    public static boolean unloadJar(String path, Consumer<Map<String, Class<?>>> call) {
        // 获取加载当前jar的类加载器
        JarDynamicLoadClassLoader jarDynamicLoadClassLoader = pluginClassLoaderCenter.get(path);
        if (jarDynamicLoadClassLoader == null) {
            return true;
        }
        if (call != null) {
            try {
                call.accept(jarDynamicLoadClassLoader.getLoadedClasses());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            // 从类加载器底层的classes中移除连接
            Field field = ClassLoader.class.getDeclaredField("classes");
            field.setAccessible(true);
            Vector<Class<?>> classes = (Vector<Class<?>>) field.get(jarDynamicLoadClassLoader);
            classes.removeAllElements();
            // 移除类加载器的引用
            pluginClassLoaderCenter.remove(path);
            // 卸载类加载器
            jarDynamicLoadClassLoader.unload();
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error("动态卸载的类，从类加载器中卸载失败");
            e.printStackTrace();
            return false;
        }
        log.info("{} 动态卸载成功", path);
        return true;
    }

    public static boolean unloadJar(String path) {
        return unloadJar(path, null);
    }
}
